package dk.mirasola.systemtraining.bridgewidgets.shared.factory;

import dk.mirasola.systemtraining.bridgewidgets.shared.model.Card;
import dk.mirasola.systemtraining.bridgewidgets.shared.model.Distribution;
import dk.mirasola.systemtraining.bridgewidgets.shared.model.Hand;
import dk.mirasola.systemtraining.bridgewidgets.shared.model.Seat;
import dk.mirasola.systemtraining.bridgewidgets.shared.model.Suit;

import java.util.HashSet;
import java.util.Set;

public class DistributionFactory {
    public static final Seat[] SEATS = new Seat[]{Seat.NORTH, Seat.EAST, Seat.SOUTH, Seat.WEST};
    public static final Suit[] SUITS = new Suit[]{Suit.SPADE, Suit.HEART, Suit.DIAMOND, Suit.CLUB};
    public static final char HAND_SUIT_DELIMITER = ':';

    public static String distributionToString(Distribution distribution) {
        if (distribution == null) {
            throw new NullPointerException();
        }

        StringBuilder sb = new StringBuilder();
        for (Seat seat : SEATS) {
            Hand hand = distribution.getHand(seat);
            if (hand != null) {
                for (Suit suit : SUITS) {
                    Set<Card> cards = hand.getCards(suit);
                    for (Card card : cards) {
                        sb.append(rangToString(card.getRang()));
                    }
                    if (suit != Suit.CLUB || seat != Seat.WEST) {
                        sb.append(HAND_SUIT_DELIMITER);
                    }
                }
            } else {
                for (int i = 0 ; i < (seat != Seat.WEST ? 4 : 3) ; i++) {
                    sb.append(HAND_SUIT_DELIMITER);
                }
            }
        }
        return sb.toString();
    }

    private static String rangToString(Card.Rang rang) {
        switch (rang) {
            case ACE:
                return "A";
            case KING:
                return "K";
            case QUEEN:
                return "Q";
            case JACK:
                return "J";
            case TEN:
                return "T";
            case NINE:
                return "9";
            case EIGTH:
                return "8";
            case SEVEN:
                return "7";
            case SIX:
                return "6";
            case FIVE:
                return "5";
            case FOUR:
                return "4";
            case THREE:
                return "3";
            case TWO:
                return "2";
            default:
                throw new RuntimeException("Unknown rang "+rang);
        }
    }

    public static Distribution stringToDistribution(String str) {
        Distribution distribution = new Distribution();
        Seat seat = Seat.NORTH;
        Suit suit = Suit.SPADE;
        Set<Card> cards = new HashSet<Card>();
        for (int i= 0 ; i < str.length() ; i++) {
            char c = str.charAt(i);
            if (c == HAND_SUIT_DELIMITER) {
                switch (suit) {
                    case SPADE:
                        suit = Suit.HEART;
                        break;
                    case HEART:
                        suit = Suit.DIAMOND;
                        break;
                    case DIAMOND:
                        suit = Suit.CLUB;
                        break;
                    case CLUB:
                        suit = Suit.SPADE;
                        if (cards.size() > 0) {
                            distribution.setHand(seat,Hand.create(cards,false));
                            cards = new HashSet<Card>();
                        }
                        switch (seat) {
                            case NORTH:
                                seat = Seat.EAST;
                                break;
                            case EAST:
                                seat = Seat.SOUTH;
                                break;
                            case SOUTH:
                                seat = Seat.WEST;
                                break;
                            case WEST:
                                throw new RuntimeException("cannot parse "+str+" to distribution");
                        }
                        break;
                }
            } else {
                Card.Rang rang = stringToRang(c);
                for (Card card : Card.values(suit)) {
                    if (card.getRang() == rang) {
                        cards.add(card);
                        break;
                    }
                }
            }
        }
        if (cards.size() > 0) {
            distribution.setHand(seat,Hand.create(cards,false));
        }
        return distribution;
    }

    private static Card.Rang stringToRang(char c) {
        switch (c) {
            case 'A':
                return Card.Rang.ACE;
            case 'K':
                return Card.Rang.KING;
            case 'Q':
                return Card.Rang.QUEEN;
            case 'J':
                return Card.Rang.JACK;
            case 'T':
                return Card.Rang.TEN;
            case '9':
                return Card.Rang.NINE;
            case '8':
                return Card.Rang.EIGTH;
            case '7':
                return Card.Rang.SEVEN;
            case '6':
                return Card.Rang.SIX;
            case '5':
                return Card.Rang.FIVE;
            case '4':
                return Card.Rang.FOUR;
            case '3':
                return Card.Rang.THREE;
            case '2':
                return Card.Rang.TWO;
            default:
                throw new RuntimeException("Unknown rang string :"+c);
        }
    }

    private DistributionFactory() {
    }
}
